/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package util.validation;

import util.validation.annotation.NotEmpty;
import com.toedter.calendar.JDateChooser;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.*;
import util.components.IntegerTextField;
import util.components.LongTextField;
import util.validation.annotation.Grupo;
import util.validation.validadores.*;


/**Provee métodos utiles para validar datos ingresados por el usuario.
 *
 * @author raul
 */
public class GestorValidacion {
    
    private  List<String> mensajes;
    
    /**Verifica que el objeto pasado devuelve los campos minimos requeridos correctamente.
     * La condicion es que LA EVALUACION DE LOS METODOS A VALIDAR NO DEBE ALTERAR EL ESTADO
     * DEL OBJETO formulario.
     * Si no valida devuelve los mensajes de error correspondientes.
     * 
     * @param formulario el objeto para el que se validaran sus metodos anotados
     * 
     * @return null si el objeto valida. Sino un vector con los mensajes de 
     * error correspondientes
     */
    public void validar(Object formulario){
        //iniciar lista de mensajes de error
        mensajes = new ArrayList<String>();
        //1- obtener la clase y sus metodos
        //3- para cada metodo realizar las validaciones
        for (Method m : formulario.getClass().getDeclaredMethods()){
                validarNotEmpty(m, formulario);
        }
    }
    
    /**
     * Valida los campos del formulario que estan anotados con @Grupo y el
     * parametro numero de la anotacion es igual al especificado en numeroGrupo.
     * 
     * @param formulario
     * @param numeroGrupo 
     */
    public void validarGrupo(Object formulario, int numeroGrupo) {
        mensajes = new ArrayList<String>();
        
        for (Method m : formulario.getClass().getDeclaredMethods()){
            // 
               if (m.isAnnotationPresent(Grupo.class)
                       && numeroGrupo == m.getAnnotation(Grupo.class).numero()) {
                validarNotEmpty(m, formulario);
            }
        }
        
    }

    public List<String> getMensajes() {
        return mensajes;
    }
    
    /**
     * 
     * @return verdadero si el formulario valida
     */
    public boolean validaFormulario(){
        return mensajes.isEmpty();
    }

    private void validarNotEmpty(Method metodo, Object formulario){
        //      3.3.1- si tiene la anotacion @NotEmpty y 
                if(metodo.isAnnotationPresent(NotEmpty.class)) {
                    IValidador validador = crearValidador(invocarMetodo(metodo, formulario));
                    if (validador.devuelveVacio())
        //          3.3.1.1- alistar mensaje de error
                        mensajes.add(metodo.getAnnotation(NotEmpty.class).mensaje().equals("")?
                        //mensaje a partir del nombre del metodo
                            "El campo "+obtenerNombreCampo(metodo.getName()) +" no es opcional.":
                        //mensaje personalizado indicado en la anotación
                            metodo.getAnnotation(NotEmpty.class).mensaje());
                }
    }
    
    /**Obtiene el nombre del campo que corresponde al metodo validado.
     * Quita el prefijo "get" y el sufijo de tres letras y 
     * separa las palabras con espacios.
     * 
     * Ej: si el metodo se llama "getNombreCampoTxt" devuelve "Nombre Campo".
     * 
     * @return el nombre del campo que se esta validando
     */
    protected String obtenerNombreCampo(String nombreMetodo){
        return nombreMetodo.substring(3, nombreMetodo.length()-3)
                .replaceAll("(?<=[a-z])(?=[A-Z])", " ");
                //El patron "(?<=[a-z])(?=[A-Z])" representa el espacio entre 
                //una minuscula seguida de un mayuscula
    }
    
    /**Invoca el metodo especificado en el objecto especificado
     * 
     * @param metodo
     * @param objeto
     * @return 
     */
    protected Object invocarMetodo(Method metodo, Object objeto){
        try { 
            return metodo.invoke(objeto);
        } catch (IllegalAccessException ex) {
            Logger.getLogger(GestorValidacion.class.getName()).log(Level.SEVERE, null, ex);
        } catch (IllegalArgumentException ex) {
            Logger.getLogger(GestorValidacion.class.getName()).log(Level.SEVERE, null, ex);
        } catch (InvocationTargetException ex) {
            Logger.getLogger(GestorValidacion.class.getName()).log(Level.SEVERE, null, ex);
        }
        return null;
    }
    
    /**Crea un objeto Validador que sabe como leer un componente especifico de
     * acuerdo con su tipo.
     * 
     * @param componente
     * @return 
     */
    protected IValidador crearValidador(Object componente) {
        return componente instanceof LongTextField? new ValidadorLTxt((LongTextField)componente):
                componente instanceof IntegerTextField? new ValidadorITxt((IntegerTextField)componente):
                componente instanceof JFormattedTextField? new ValidadorTxt((JFormattedTextField)componente):
                componente instanceof JTextField? new ValidadorTxt((JTextField) componente):
                componente instanceof JComboBox ? new ValidadorCmb((JComboBox)componente):
                componente instanceof JDateChooser ? new ValidadorDate((JDateChooser)componente):
                componente instanceof JList ? new ValidadorLst((JList)componente):
                null;
    }
    
      
}
